#include <z80.h>
#include <stddef.h>
#include <stdbool.h>
#include <string.h>
#include <malloc.h>
#include "vdp.h"
#include "screen.h"

// vdp device
static struct vdp_device _vdp_dev;

// screen back buffer
static char *_video_mem = NULL;

// input buffer
static char _command[64] = { 0 };

// cursor position
static uint16_t _pos = 0;

// max cursor position
static uint16_t _max_pos = 0;

// row count
static uint8_t _rows = 0;

// column count
static uint8_t _cols = 0;

// blink
static bool _blink = false;

// blink counter
static uint8_t _blink_counter = 0;

// font
static const uint8_t _font[2048] = {
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x38,0x44,0x6C,0x44,0x54,0x44,0x38,0x00,
    0x38,0x7C,0x54,0x7C,0x44,0x7C,0x38,0x00,
    0x00,0x28,0x7C,0x7C,0x7C,0x38,0x10,0x00,
    0x00,0x10,0x38,0x7C,0x7C,0x38,0x10,0x00,
    0x10,0x38,0x38,0x10,0x7C,0x7C,0x10,0x00,
    0x00,0x10,0x38,0x7C,0x7C,0x10,0x38,0x00,
    0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,
    0xFC,0xFC,0xFC,0xCC,0xCC,0xFC,0xFC,0xFC,
    0x00,0x00,0x78,0x48,0x48,0x78,0x00,0x00,
    0xFC,0xFC,0x84,0xB4,0xB4,0x84,0xFC,0xFC,
    0x00,0x1C,0x0C,0x34,0x48,0x48,0x30,0x00,
    0x38,0x44,0x44,0x38,0x10,0x38,0x10,0x00,
    0x10,0x18,0x14,0x10,0x30,0x70,0x60,0x00,
    0x0C,0x34,0x2C,0x34,0x2C,0x6C,0x60,0x00,
    0x00,0x54,0x38,0x6C,0x38,0x54,0x00,0x00,
    0x20,0x30,0x38,0x3C,0x38,0x30,0x20,0x00,
    0x08,0x18,0x38,0x78,0x38,0x18,0x08,0x00,
    0x10,0x38,0x7C,0x10,0x7C,0x38,0x10,0x00,
    0x28,0x28,0x28,0x28,0x28,0x00,0x28,0x00,
    0x3C,0x54,0x54,0x34,0x14,0x14,0x14,0x00,
    0x38,0x44,0x30,0x28,0x18,0x44,0x38,0x00,
    0x00,0x00,0x00,0x00,0x00,0x78,0x78,0x00,
    0x10,0x38,0x7C,0x10,0x7C,0x38,0x10,0x38,
    0x10,0x38,0x7C,0x10,0x10,0x10,0x10,0x00,
    0x10,0x10,0x10,0x10,0x7C,0x38,0x10,0x00,
    0x00,0x10,0x18,0x7C,0x18,0x10,0x00,0x00,
    0x00,0x10,0x30,0x7C,0x30,0x10,0x00,0x00,
    0x00,0x00,0x00,0x40,0x40,0x40,0x7C,0x00,
    0x00,0x28,0x28,0x7C,0x28,0x28,0x00,0x00,
    0x10,0x10,0x38,0x38,0x7C,0x7C,0x00,0x00,
    0x7C,0x7C,0x38,0x38,0x10,0x10,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x10,0x38,0x38,0x10,0x10,0x00,0x10,0x00,
    0x6C,0x6C,0x48,0x00,0x00,0x00,0x00,0x00,
    0x00,0x28,0x7C,0x28,0x28,0x7C,0x28,0x00,
    0x20,0x38,0x40,0x30,0x08,0x70,0x10,0x00,
    0x64,0x64,0x08,0x10,0x20,0x4C,0x4C,0x00,
    0x20,0x50,0x50,0x20,0x54,0x48,0x34,0x00,
    0x30,0x30,0x20,0x00,0x00,0x00,0x00,0x00,
    0x10,0x20,0x20,0x20,0x20,0x20,0x10,0x00,
    0x20,0x10,0x10,0x10,0x10,0x10,0x20,0x00,
    0x00,0x28,0x38,0x7C,0x38,0x28,0x00,0x00,
    0x00,0x10,0x10,0x7C,0x10,0x10,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x20,
    0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,
    0x00,0x04,0x08,0x10,0x20,0x40,0x00,0x00,
    0x38,0x44,0x4C,0x54,0x64,0x44,0x38,0x00,
    0x10,0x30,0x10,0x10,0x10,0x10,0x38,0x00,
    0x38,0x44,0x04,0x18,0x20,0x40,0x7C,0x00,
    0x38,0x44,0x04,0x38,0x04,0x44,0x38,0x00,
    0x08,0x18,0x28,0x48,0x7C,0x08,0x08,0x00,
    0x7C,0x40,0x40,0x78,0x04,0x44,0x38,0x00,
    0x18,0x20,0x40,0x78,0x44,0x44,0x38,0x00,
    0x7C,0x04,0x08,0x10,0x20,0x20,0x20,0x00,
    0x38,0x44,0x44,0x38,0x44,0x44,0x38,0x00,
    0x38,0x44,0x44,0x3C,0x04,0x08,0x30,0x00,
    0x00,0x00,0x30,0x30,0x00,0x30,0x30,0x00,
    0x00,0x00,0x30,0x30,0x00,0x30,0x30,0x20,
    0x08,0x10,0x20,0x40,0x20,0x10,0x08,0x00,
    0x00,0x00,0x7C,0x00,0x00,0x7C,0x00,0x00,
    0x20,0x10,0x08,0x04,0x08,0x10,0x20,0x00,
    0x38,0x44,0x04,0x18,0x10,0x00,0x10,0x00,
    0x38,0x44,0x5C,0x54,0x5C,0x40,0x38,0x00,
    0x38,0x44,0x44,0x44,0x7C,0x44,0x44,0x00,
    0x78,0x44,0x44,0x78,0x44,0x44,0x78,0x00,
    0x38,0x44,0x40,0x40,0x40,0x44,0x38,0x00,
    0x78,0x44,0x44,0x44,0x44,0x44,0x78,0x00,
    0x7C,0x40,0x40,0x78,0x40,0x40,0x7C,0x00,
    0x7C,0x40,0x40,0x78,0x40,0x40,0x40,0x00,
    0x38,0x44,0x40,0x5C,0x44,0x44,0x3C,0x00,
    0x44,0x44,0x44,0x7C,0x44,0x44,0x44,0x00,
    0x38,0x10,0x10,0x10,0x10,0x10,0x38,0x00,
    0x04,0x04,0x04,0x04,0x44,0x44,0x38,0x00,
    0x44,0x48,0x50,0x60,0x50,0x48,0x44,0x00,
    0x40,0x40,0x40,0x40,0x40,0x40,0x7C,0x00,
    0x44,0x6C,0x54,0x44,0x44,0x44,0x44,0x00,
    0x44,0x64,0x54,0x4C,0x44,0x44,0x44,0x00,
    0x38,0x44,0x44,0x44,0x44,0x44,0x38,0x00,
    0x78,0x44,0x44,0x78,0x40,0x40,0x40,0x00,
    0x38,0x44,0x44,0x44,0x54,0x48,0x34,0x00,
    0x78,0x44,0x44,0x78,0x48,0x44,0x44,0x00,
    0x38,0x44,0x40,0x38,0x04,0x44,0x38,0x00,
    0x7C,0x10,0x10,0x10,0x10,0x10,0x10,0x00,
    0x44,0x44,0x44,0x44,0x44,0x44,0x38,0x00,
    0x44,0x44,0x44,0x44,0x44,0x28,0x10,0x00,
    0x44,0x44,0x54,0x54,0x54,0x54,0x28,0x00,
    0x44,0x44,0x28,0x10,0x28,0x44,0x44,0x00,
    0x44,0x44,0x44,0x28,0x10,0x10,0x10,0x00,
    0x78,0x08,0x10,0x20,0x40,0x40,0x78,0x00,
    0x38,0x20,0x20,0x20,0x20,0x20,0x38,0x00,
    0x00,0x40,0x20,0x10,0x08,0x04,0x00,0x00,
    0x38,0x08,0x08,0x08,0x08,0x08,0x38,0x00,
    0x10,0x28,0x44,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFC,
    0x30,0x30,0x10,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x38,0x04,0x3C,0x44,0x3C,0x00,
    0x40,0x40,0x78,0x44,0x44,0x44,0x78,0x00,
    0x00,0x00,0x38,0x44,0x40,0x44,0x38,0x00,
    0x04,0x04,0x3C,0x44,0x44,0x44,0x3C,0x00,
    0x00,0x00,0x38,0x44,0x78,0x40,0x38,0x00,
    0x18,0x20,0x20,0x78,0x20,0x20,0x20,0x00,
    0x00,0x00,0x3C,0x44,0x44,0x3C,0x04,0x38,
    0x40,0x40,0x70,0x48,0x48,0x48,0x48,0x00,
    0x10,0x00,0x10,0x10,0x10,0x10,0x18,0x00,
    0x08,0x00,0x18,0x08,0x08,0x08,0x48,0x30,
    0x40,0x40,0x48,0x50,0x60,0x50,0x48,0x00,
    0x10,0x10,0x10,0x10,0x10,0x10,0x18,0x00,
    0x00,0x00,0x68,0x54,0x54,0x44,0x44,0x00,
    0x00,0x00,0x70,0x48,0x48,0x48,0x48,0x00,
    0x00,0x00,0x38,0x44,0x44,0x44,0x38,0x00,
    0x00,0x00,0x78,0x44,0x44,0x44,0x78,0x40,
    0x00,0x00,0x3C,0x44,0x44,0x44,0x3C,0x04,
    0x00,0x00,0x58,0x24,0x20,0x20,0x70,0x00,
    0x00,0x00,0x38,0x40,0x38,0x04,0x38,0x00,
    0x00,0x20,0x78,0x20,0x20,0x28,0x10,0x00,
    0x00,0x00,0x48,0x48,0x48,0x58,0x28,0x00,
    0x00,0x00,0x44,0x44,0x44,0x28,0x10,0x00,
    0x00,0x00,0x44,0x44,0x54,0x7C,0x28,0x00,
    0x00,0x00,0x48,0x48,0x30,0x48,0x48,0x00,
    0x00,0x00,0x48,0x48,0x48,0x38,0x10,0x60,
    0x00,0x00,0x78,0x08,0x30,0x40,0x78,0x00,
    0x18,0x20,0x20,0x60,0x20,0x20,0x18,0x00,
    0x10,0x10,0x10,0x00,0x10,0x10,0x10,0x00,
    0x30,0x08,0x08,0x0C,0x08,0x08,0x30,0x00,
    0x28,0x50,0x00,0x00,0x00,0x00,0x00,0x00,
    0x10,0x38,0x6C,0x44,0x44,0x7C,0x00,0x00,
    0x38,0x44,0x40,0x40,0x44,0x38,0x10,0x30,
    0x48,0x00,0x48,0x48,0x48,0x58,0x28,0x00,
    0x0C,0x00,0x38,0x44,0x78,0x40,0x38,0x00,
    0x38,0x00,0x38,0x04,0x3C,0x44,0x3C,0x00,
    0x28,0x00,0x38,0x04,0x3C,0x44,0x3C,0x00,
    0x30,0x00,0x38,0x04,0x3C,0x44,0x3C,0x00,
    0x38,0x28,0x38,0x04,0x3C,0x44,0x3C,0x00,
    0x00,0x38,0x44,0x40,0x44,0x38,0x10,0x30,
    0x38,0x00,0x38,0x44,0x78,0x40,0x38,0x00,
    0x28,0x00,0x38,0x44,0x78,0x40,0x38,0x00,
    0x30,0x00,0x38,0x44,0x78,0x40,0x38,0x00,
    0x28,0x00,0x10,0x10,0x10,0x10,0x18,0x00,
    0x10,0x28,0x00,0x10,0x10,0x10,0x18,0x00,
    0x20,0x00,0x10,0x10,0x10,0x10,0x18,0x00,
    0x28,0x00,0x10,0x28,0x44,0x7C,0x44,0x00,
    0x38,0x28,0x38,0x6C,0x44,0x7C,0x44,0x00,
    0x0C,0x00,0x7C,0x40,0x78,0x40,0x7C,0x00,
    0x00,0x00,0x78,0x14,0x7C,0x50,0x3C,0x00,
    0x3C,0x50,0x50,0x7C,0x50,0x50,0x5C,0x00,
    0x38,0x00,0x30,0x48,0x48,0x48,0x30,0x00,
    0x28,0x00,0x30,0x48,0x48,0x48,0x30,0x00,
    0x60,0x00,0x30,0x48,0x48,0x48,0x30,0x00,
    0x38,0x00,0x48,0x48,0x48,0x58,0x28,0x00,
    0x60,0x00,0x48,0x48,0x48,0x58,0x28,0x00,
    0x28,0x00,0x48,0x48,0x48,0x38,0x10,0x60,
    0x48,0x30,0x48,0x48,0x48,0x48,0x30,0x00,
    0x28,0x00,0x48,0x48,0x48,0x48,0x30,0x00,
    0x00,0x10,0x38,0x40,0x40,0x38,0x10,0x00,
    0x18,0x24,0x20,0x78,0x20,0x24,0x5C,0x00,
    0x44,0x28,0x10,0x7C,0x10,0x7C,0x10,0x00,
    0x60,0x50,0x50,0x68,0x5C,0x48,0x48,0x00,
    0x08,0x14,0x10,0x38,0x10,0x10,0x50,0x20,
    0x18,0x00,0x38,0x04,0x3C,0x44,0x3C,0x00,
    0x18,0x00,0x10,0x10,0x10,0x10,0x18,0x00,
    0x18,0x00,0x30,0x48,0x48,0x48,0x30,0x00,
    0x18,0x00,0x48,0x48,0x48,0x58,0x28,0x00,
    0x28,0x50,0x00,0x70,0x48,0x48,0x48,0x00,
    0x28,0x50,0x00,0x48,0x68,0x58,0x48,0x00,
    0x38,0x04,0x3C,0x44,0x3C,0x00,0x3C,0x00,
    0x30,0x48,0x48,0x48,0x30,0x00,0x78,0x00,
    0x10,0x00,0x10,0x30,0x40,0x44,0x38,0x00,
    0x00,0x00,0x7C,0x40,0x40,0x40,0x00,0x00,
    0x00,0x00,0xFC,0x04,0x04,0x00,0x00,0x00,
    0x40,0x48,0x50,0x38,0x44,0x08,0x1C,0x00,
    0x40,0x48,0x50,0x2C,0x54,0x1C,0x04,0x00,
    0x10,0x00,0x10,0x10,0x38,0x38,0x10,0x00,
    0x00,0x00,0x24,0x48,0x24,0x00,0x00,0x00,
    0x00,0x00,0x48,0x24,0x48,0x00,0x00,0x00,
    0x54,0x00,0xA8,0x00,0x54,0x00,0xA8,0x00,
    0x54,0xA8,0x54,0xA8,0x54,0xA8,0x54,0xA8,
    0xA8,0xFC,0x54,0xFC,0xA8,0xFC,0x54,0xFC,
    0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
    0x10,0x10,0x10,0xF0,0x10,0x10,0x10,0x10,
    0x10,0xF0,0x10,0xF0,0x10,0x10,0x10,0x10,
    0x50,0x50,0x50,0xD0,0x50,0x50,0x50,0x50,
    0x00,0x00,0x00,0xF0,0x50,0x50,0x50,0x50,
    0x00,0xF0,0x10,0xF0,0x10,0x10,0x10,0x10,
    0x50,0xD0,0x10,0xD0,0x50,0x50,0x50,0x50,
    0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,
    0x00,0xF0,0x10,0xD0,0x50,0x50,0x50,0x50,
    0x50,0xD0,0x10,0xF0,0x00,0x00,0x00,0x00,
    0x50,0x50,0x50,0xF0,0x00,0x00,0x00,0x00,
    0x10,0xF0,0x10,0xF0,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0xF0,0x10,0x10,0x10,0x10,
    0x10,0x10,0x10,0x1C,0x00,0x00,0x00,0x00,
    0x10,0x10,0x10,0xFC,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0xFC,0x10,0x10,0x10,0x10,
    0x10,0x10,0x10,0x1C,0x10,0x10,0x10,0x10,
    0x00,0x00,0x00,0xFC,0x00,0x00,0x00,0x00,
    0x10,0x10,0x10,0xFC,0x10,0x10,0x10,0x10,
    0x10,0x1C,0x10,0x1C,0x10,0x10,0x10,0x10,
    0x50,0x50,0x50,0x5C,0x50,0x50,0x50,0x50,
    0x50,0x5C,0x40,0x7C,0x00,0x00,0x00,0x00,
    0x00,0x7C,0x40,0x5C,0x50,0x50,0x50,0x50,
    0x50,0xDC,0x00,0xFC,0x00,0x00,0x00,0x00,
    0x00,0xFC,0x00,0xDC,0x50,0x50,0x50,0x50,
    0x50,0x5C,0x40,0x5C,0x50,0x50,0x50,0x50,
    0x00,0xFC,0x00,0xFC,0x00,0x00,0x00,0x00,
    0x50,0xDC,0x00,0xDC,0x50,0x50,0x50,0x50,
    0x10,0xFC,0x00,0xFC,0x00,0x00,0x00,0x00,
    0x50,0x50,0x50,0xFC,0x00,0x00,0x00,0x00,
    0x00,0xFC,0x00,0xFC,0x10,0x10,0x10,0x10,
    0x00,0x00,0x00,0xFC,0x50,0x50,0x50,0x50,
    0x50,0x50,0x50,0x7C,0x00,0x00,0x00,0x00,
    0x10,0x1C,0x10,0x1C,0x00,0x00,0x00,0x00,
    0x00,0x1C,0x10,0x1C,0x10,0x10,0x10,0x10,
    0x00,0x00,0x00,0x7C,0x50,0x50,0x50,0x50,
    0x50,0x50,0x50,0xDC,0x50,0x50,0x50,0x50,
    0x10,0xFC,0x00,0xFC,0x10,0x10,0x10,0x10,
    0x10,0x10,0x10,0xF0,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x1C,0x10,0x10,0x10,0x10,
    0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,
    0x00,0x00,0x00,0x00,0xFC,0xFC,0xFC,0xFC,
    0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,
    0x1C,0x1C,0x1C,0x1C,0x1C,0x1C,0x1C,0x1C,
    0xFC,0xFC,0xFC,0xFC,0x00,0x00,0x00,0x00,
    0x00,0x00,0x34,0x48,0x48,0x34,0x00,0x00,
    0x00,0x70,0x48,0x70,0x48,0x48,0x70,0x40,
    0x78,0x48,0x40,0x40,0x40,0x40,0x40,0x00,
    0x00,0x7C,0x28,0x28,0x28,0x28,0x28,0x00,
    0x78,0x48,0x20,0x10,0x20,0x48,0x78,0x00,
    0x00,0x00,0x3C,0x48,0x48,0x30,0x00,0x00,
    0x00,0x00,0x48,0x48,0x48,0x70,0x40,0x40,
    0x00,0x00,0x28,0x50,0x10,0x10,0x10,0x00,
    0x38,0x10,0x38,0x44,0x38,0x10,0x38,0x00,
    0x30,0x48,0x48,0x78,0x48,0x48,0x30,0x00,
    0x00,0x38,0x44,0x44,0x28,0x28,0x6C,0x00,
    0x30,0x40,0x20,0x10,0x38,0x48,0x30,0x00,
    0x00,0x00,0x28,0x54,0x54,0x28,0x00,0x00,
    0x00,0x10,0x38,0x54,0x54,0x38,0x10,0x00,
    0x00,0x38,0x40,0x78,0x40,0x38,0x00,0x00,
    0x00,0x30,0x48,0x48,0x48,0x48,0x00,0x00,
    0x00,0x78,0x00,0x78,0x00,0x78,0x00,0x00,
    0x00,0x10,0x38,0x10,0x00,0x38,0x00,0x00,
    0x40,0x30,0x08,0x30,0x40,0x00,0x78,0x00,
    0x08,0x30,0x40,0x30,0x08,0x00,0x78,0x00,
    0x00,0x08,0x14,0x10,0x10,0x10,0x10,0x10,
    0x10,0x10,0x10,0x10,0x10,0x50,0x20,0x00,
    0x00,0x10,0x00,0x7C,0x00,0x10,0x00,0x00,
    0x00,0x28,0x50,0x00,0x28,0x50,0x00,0x00,
    0x30,0x48,0x48,0x30,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,
    0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,
    0x00,0x1C,0x10,0x10,0x50,0x50,0x20,0x00,
    0x50,0x28,0x28,0x28,0x00,0x00,0x00,0x00,
    0x60,0x10,0x20,0x70,0x00,0x00,0x00,0x00,
    0x00,0x00,0x78,0x78,0x78,0x78,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};

// vdp vblank callback
void on_vblank_callback(void) {
    uint8_t status = _vdp_dev.status();
    if (_video_mem != NULL)
        _vdp_dev.fill_name_table(_video_mem, _max_pos + 1);
}

static void scroll()
{
    if (_video_mem == NULL)
        return;

   memmove(_video_mem, _video_mem + _cols, _max_pos - _cols + 1);
   bzero(_video_mem + _max_pos - _cols + 1, _cols);
   _pos = _max_pos - _cols + 1;
}

static void screen_clear()
{
    if (_video_mem == NULL)
        return;

    _pos = 0;
    bzero(_video_mem, _max_pos + 1);
}

static void screen_putchar(char c)
{
    if (_video_mem == NULL)
        return;

    if (c == '\n') {
        _video_mem[_pos] = 0;
        _pos = (_pos / _cols + 1) * _cols;
    } else {
        _video_mem[_pos] = c;
        _pos++;
    }

    if (_pos > _max_pos)
        scroll();
}

static void screen_print(char* str)
{
    if (_video_mem == NULL)
        return;
    char c;
    while ((c = *str++) != '\0')
        screen_putchar(c);
}

static void screen_write(uint8_t x, uint8_t y, char c)
{
    if (_video_mem == NULL)
        return;

    if (x >= _cols || y >= _rows)
        return;

    _video_mem[y * _cols + x] = c;
}

void screen_update()
{
    if (_video_mem == NULL)
        return;

    if (!(_vdp_dev.status() & VDP_INT))
        return;

    if (_blink_counter++ < 5) {
        _video_mem[_pos] = _blink ? 219 : 0;
    } else {
        _blink_counter = 0;
        _blink = !_blink;
    } 

    _vdp_dev.fill_name_table(_video_mem, _max_pos + 1);
}

static void screen_input(char* buf, uint16_t len, struct kbd_device* dev)
{
    if (_video_mem == NULL)
        return;

    if (dev == NULL)
        return;

    if (buf == NULL)
        return;

    bzero(buf, len);
    uint8_t key = 0;
    uint8_t index = 0;
    char ch;
    for (;;) {
        key = dev->poll_key();
        if (key != 0 && !(key & KBD_VK_MASK)) {
            if (key == KBD_VK_ENTER) {
                break;
            } else if (key == KBD_VK_BACKSPACE) {
                if (index > 0) {
                    _command[index--] = 0;
                    _command[index] = 0;
                    _video_mem[_pos--] = 0;
                    _video_mem[_pos] = 0;
                }
            } else if (index < sizeof(_command) - 1) {
                ch = dev->to_ascii(key);
                _command[index++] = ch;
                screen_putchar(ch);
            }
        }
        screen_update();
    }
    screen_putchar('\n');
    memcpy(buf, _command, index);
}

void screen_init(struct screen_device *dev)
{
    _pos = _max_pos = 0;
    _rows = _cols = 0;
    
    dev->clear = screen_clear;
    dev->putchar = screen_putchar;
    dev->print = screen_print;
    dev->input = screen_input;
    dev->write = screen_write;
    dev->update = screen_update;

    // init vdp
    struct vdp_context ctx;
    ctx.mode = VDP_TEXT_MODE;
    ctx.size = VDP_SIZE_8_8;
    ctx.mag = VDP_MAG_OFF;
    ctx.text_color = VDP_CLR_WHITE;
    ctx.back_color = VDP_CLR_BLACK;
    ctx.interrupt_handler = on_vblank_callback;
    vdp_init(&_vdp_dev, &ctx);

    // allocate memory
    if (ctx.mode == VDP_TEXT_MODE) {
        _rows = 24;
        _cols = 40;
        _max_pos = 959;
        _video_mem = (char*)malloc(960);
        bzero(_video_mem, 960);
    } else if (ctx.mode == VDP_GRAPHIC_MODE_1) {
        _rows = 24;
        _cols = 32;
        _max_pos = 767;
        _video_mem = (char*)malloc(768);
        bzero(_video_mem, 768);
    } else {
        _max_pos = 0;
        _video_mem = (char*)malloc(0);
        bzero(_video_mem, 0);
    }

    // insufficient memory
    if (_video_mem == NULL)
        return;
    
    // fill patterns
    _vdp_dev.fill_pattern_table(_font, sizeof(_font));
    _vdp_dev.fill_name_table(_video_mem, _max_pos + 1);
    _vdp_dev.interrupt_enable(false);
}